const catsOf = (p) => p.category.split(',').map((c) => c.trim());

function FilterChip({ label, active, onClick, dark }) {
  const [h, setH] = React.useState(false);
  return (
    <button onClick={onClick} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        border: 'none', cursor: 'pointer', borderRadius: 999, padding: '7px 14px',
        fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase',
        backgroundColor: active ? (dark ? 'var(--white)' : 'var(--black)') : h ? (dark ? 'rgba(255,255,255,0.14)' : 'rgba(10,10,10,0.1)') : (dark ? 'rgba(255,255,255,0.08)' : 'rgba(10,10,10,0.05)'),
        color: active ? (dark ? 'var(--black)' : 'var(--white)') : (dark ? 'var(--gray-on-dark-200)' : 'var(--gray-600)'), transition: 'background-color .25s ease, color .25s ease',
      }}>{label}</button>
  );
}

/* Thumbnail version of the hero joke: the queue, the box, the four survivors,
   scaled down to a card plate. Props are dropped at this size - they would read
   as specks - but the size difference still tells the story. */
function HeroMini({ gradient, hover }) {
  return (
    <div style={{ position: 'relative', width: '100%', height: '100%', borderRadius: 10, overflow: 'hidden', background: gradient }}>
      <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(120% 90% at 16% 6%, rgba(255,255,255,0.24), rgba(255,255,255,0) 62%)' }} />
      <div style={{ position: 'absolute', left: 8, right: 8, bottom: 9, display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 5, transform: hover ? 'translateY(-2px)' : 'none', transition: 'transform .3s cubic-bezier(.22,1,.36,1)' }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', gap: 2.5, minWidth: 0 }}>
          {[0, 1, 2, 3].map((i) => (
            <div key={i} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1, opacity: 0.34 - i * 0.035 }}>
              <div style={{ width: 4, height: 4, borderRadius: '50%', background: 'var(--white)' }} />
              <div style={{ width: 6, height: 7, borderRadius: '3px 3px 1px 1px', background: 'var(--white)' }} />
            </div>
          ))}
        </div>
        <div style={{ width: 20, height: 13, borderRadius: 3, background: 'rgba(255,255,255,0.16)', border: '1px solid rgba(255,255,255,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 2, flexShrink: 0 }}>
          {[0, 1, 2].map((i) => <span key={i} style={{ width: 2, height: 2, borderRadius: '50%', background: 'var(--white)' }} />)}
        </div>
        <div style={{ display: 'flex', alignItems: 'flex-end', gap: 4, flexShrink: 0 }}>
          {[0, 1, 2, 3].map((i) => (
            <div key={i} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1.5 }}>
              <div style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--white)' }} />
              <div style={{ width: 11, height: 13, borderRadius: '5px 5px 2px 2px', background: 'rgba(255,255,255,' + (0.92 - i * 0.06).toFixed(2) + ')' }} />
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function FeaturedPost({ post, t, href, onOpen, dark }) {
  const [h, setH] = React.useState(false);
  const { Icon } = window.SevcikMarketingDesignSystem_3203fa;
  return (
    <a href={href} onClick={(ev) => { ev.preventDefault(); onOpen(); }}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      className="sm-blog-row"
      style={{
        display: 'grid', gridTemplateColumns: '120px 148px minmax(0, 1fr) auto', alignItems: 'center', gap: 24, textDecoration: 'none',
        padding: '20px 24px', cursor: 'pointer', borderBottom: `1.5px solid ${dark ? 'var(--border-hairline-dark)' : 'var(--gray-200)'}`,
        backgroundColor: h ? (dark ? 'rgba(255,255,255,0.06)' : 'var(--gray-150)') : 'transparent', transition: 'background-color .25s ease',
      }}>
      <div className="sm-mono" style={{ display: 'flex', flexDirection: 'column', gap: 8, fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: dark ? 'var(--gray-on-dark-500)' : 'var(--gray-500)' }}>
        <span style={{ alignSelf: 'flex-start', padding: '3px 8px', borderRadius: 999, background: dark ? 'var(--white)' : 'var(--black)', color: dark ? 'var(--black)' : 'var(--white)' }}>{t.latestBadge}</span>
        <span>{post.date.replace(/,\s*\d{4}$/, '')}</span>
      </div>
      <div style={{ height: 88, borderRadius: 10, overflow: 'hidden' }}>
        <HeroMini gradient={post.art} hover={h} />
      </div>
      <div style={{ minWidth: 0, transform: h ? 'translateX(4px)' : 'none', transition: 'transform .3s cubic-bezier(.22,1,.36,1)' }}>
        <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 22, lineHeight: 1.22, letterSpacing: '-0.015em', color: dark ? 'var(--white)' : 'var(--black)', margin: 0 }}>{post.title}</h3>
        <div style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 12.5, color: dark ? 'var(--gray-on-dark-400)' : 'var(--gray-600)', marginTop: 5 }}>{post.category}</div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexShrink: 0 }}>
        <span className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: dark ? 'var(--gray-on-dark-500)' : 'var(--gray-500)' }}>{post.read}</span>
        <span style={{ width: 34, height: 34, borderRadius: 'var(--radius-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: h ? (dark ? 'var(--white)' : 'var(--black)') : (dark ? 'rgba(255,255,255,0.08)' : 'rgba(10,10,10,0.05)'), transition: 'background-color .25s ease' }}>
          <Icon name="arrow-up-right" size={15} color={h ? (dark ? 'var(--black)' : 'var(--white)') : (dark ? 'var(--white)' : 'var(--black)')} />
        </span>
      </div>
    </a>
  );
}

function PostRow({ post, t, href, onOpen, last, dark }) {
  const [h, setH] = React.useState(false);
  const { Icon } = window.SevcikMarketingDesignSystem_3203fa;
  return (
    <a href={href} onClick={(e) => { e.preventDefault(); onOpen(); }}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      className="sm-blog-row"
      style={{
        display: 'grid', gridTemplateColumns: '120px 148px minmax(0, 1fr) auto', alignItems: 'center', gap: 24, textDecoration: 'none',
        padding: '20px 24px', cursor: 'pointer', borderBottom: last ? 'none' : `1.5px solid ${dark ? 'var(--border-hairline-dark)' : 'var(--gray-200)'}`,
        backgroundColor: h ? (dark ? 'rgba(255,255,255,0.06)' : 'var(--gray-150)') : 'transparent', transition: 'background-color .25s ease',
      }}>
      <div className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: dark ? 'var(--gray-on-dark-500)' : 'var(--gray-500)' }}>{post.date.replace(/,\s*\d{4}$/, '')}</div>
      <div />
      <div style={{ minWidth: 0, transform: h ? 'translateX(4px)' : 'none', transition: 'transform .3s cubic-bezier(.22,1,.36,1)' }}>
        <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 20, lineHeight: 1.25, letterSpacing: '-0.01em', color: dark ? 'var(--white)' : 'var(--black)', margin: 0 }}>{post.title}</h3>
        <div style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 12.5, color: dark ? 'var(--gray-on-dark-400)' : 'var(--gray-600)', marginTop: 5 }}>{post.category}</div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexShrink: 0 }}>
        <span className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: dark ? 'var(--gray-on-dark-500)' : 'var(--gray-500)' }}>{post.read}</span>
        <span style={{ width: 32, height: 32, borderRadius: 'var(--radius-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: h ? (dark ? 'var(--white)' : 'var(--black)') : (dark ? 'rgba(255,255,255,0.08)' : 'rgba(10,10,10,0.05)'), transition: 'background-color .25s ease' }}>
          <Icon name="arrow-up-right" size={15} color={h ? (dark ? 'var(--black)' : 'var(--white)') : (dark ? 'var(--white)' : 'var(--black)')} />
        </span>
      </div>
    </a>
  );
}

function BlogListing({ s, t, onBack, onOpenArticle }) {
  const theme = useReaderTheme();
  const { dark, C } = theme;
  const [cat, setCat] = React.useState(s.cats[0]);
  const list = cat === s.cats[0] ? s.posts : s.posts.filter((p) => catsOf(p).includes(cat));
  const [featured, ...rest] = list;
  const hrefOf = (p) => routeHref({ lang: s.htmlLang, screen: 'blog', slug: p.slug });
  return (
    <ScreenOverlay onClose={onBack} backLabel={t.backHome} meta={s.posts.length ? `${list.length} ${list.length === 1 ? t.article : t.articles}` : t.emptyArticles} zIndex={60} maxWidth={920} theme={theme} t={t}>
      <OverlayTitle title={t.insightsHub} blurb={s.blogBlurb} C={C} />
      {s.posts.length > 0 && (
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 24 }}>
          {s.cats.filter((c) => c === s.cats[0] || s.posts.some((p) => catsOf(p).includes(c))).map((c) => <FilterChip key={c} label={c} active={cat === c} onClick={() => setCat(c)} dark={dark} />)}
        </div>
      )}
      <div style={{ background: C.card, borderRadius: 'var(--radius-card)', overflow: 'hidden', transition: 'background-color .35s ease' }}>
        {s.posts.length === 0 && <EmptyState title={t.emptyArticles} note={t.emptyArticlesNote} gradient="var(--gradient-thumb-pink)" C={C} />}
        {featured && <FeaturedPost post={featured} t={t} href={hrefOf(featured)} onOpen={() => onOpenArticle(featured)} dark={dark} />}
        {rest.map((p, i) => <PostRow key={p.id} post={p} t={t} href={hrefOf(p)} onOpen={() => onOpenArticle(p)} last={i === rest.length - 1} dark={dark} />)}
      </div>
    </ScreenOverlay>
  );
}

/* Article body blocks. Beyond paragraphs the pieces need lists, a stat
   callout and the team-shape figure - all drawn from tokens so they follow the
   reader's light/dark choice. *word* renders as emphasis. */
function Em({ text }) {
  const parts = String(text).split(/\*([^*]+)\*/);
  return <>{parts.map((s, i) => (i % 2 ? <em key={i}>{s}</em> : s))}</>;
}

function ArticleList({ items, C }) {
  return (
    <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 12 }}>
      {items.map((it, i) => (
        <li key={i} style={{ display: 'flex', gap: 14, fontFamily: 'var(--font-body)', fontSize: 18, lineHeight: 1.6, color: C.body }}>
          <span aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', background: C.meta, flexShrink: 0, marginTop: 11 }} />
          <span><Em text={it} /></span>
        </li>
      ))}
    </ul>
  );
}

function StatCallout({ value, label, C }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'auto minmax(0, 1fr)', gap: 22, alignItems: 'center', padding: '22px 0', borderTop: `1.5px solid ${C.rule}`, borderBottom: `1.5px solid ${C.rule}` }}>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 54, lineHeight: 0.9, letterSpacing: '-0.03em', color: C.heading }}>{value}</div>
      <div style={{ fontFamily: 'var(--font-body)', fontSize: 15.5, lineHeight: 1.55, color: C.stand, textWrap: 'pretty' }}>{label}</div>
    </div>
  );
}

/* Team shape: the pyramid that folds into four roles. Left column is stacked
   blocks (one lead, three specialists, eight juniors), right column is four
   named plates plus a dashed row for the software that replaced the base. */
function TeamShape({ data, C, dark }) {
  const cell = (h, bg, key) => <div key={key} style={{ height: h, borderRadius: 4, background: bg }} />;
  const faint = dark ? 'rgba(255,255,255,0.16)' : 'var(--gray-200)';
  const mid = dark ? 'rgba(255,255,255,0.32)' : 'var(--gray-300)';
  const lab = { fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: C.meta };
  return (
    <figure style={{ margin: 0 }}>
      <div className="sm-team-shape" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 28 }}>
        <div>
          <div style={lab}>{data.thenLabel}</div>
          <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column', gap: 6 }}>
            {cell(26, mid, 'l')}
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6 }}>{[0, 1, 2].map((i) => cell(20, mid, 's' + i))}</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>{[0, 1, 2, 3, 4, 5, 6, 7].map((i) => cell(14, faint, 'j' + i))}</div>
          </div>
        </div>
        <div>
          <div style={lab}>{data.nowLabel}</div>
          <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column', gap: 6 }}>
            {data.roles.map((r, i) => (
              <div key={r} style={{ display: 'flex', alignItems: 'center', gap: 10, height: 30 }}>
                <span aria-hidden="true" style={{ width: 16, height: 16, borderRadius: 4, flexShrink: 0, background: ['var(--gradient-thumb-pink)', 'var(--gradient-thumb-cool)', 'var(--gradient-thumb-warm)', 'var(--gradient-thumb-pastel)'][i % 4] }} />
                <span style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 13.5, lineHeight: 1.2, color: C.heading }}>{r}</span>
              </div>
            ))}
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, height: 30 }}>
              <span aria-hidden="true" style={{ width: 16, height: 16, borderRadius: 4, flexShrink: 0, border: `1.5px dashed ${mid}` }} />
              <span style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 13.5, lineHeight: 1.2, color: C.meta }}>{data.softwareLabel}</span>
            </div>
          </div>
        </div>
      </div>
      <figcaption style={{ marginTop: 16, fontFamily: 'var(--font-body)', fontSize: 13.5, lineHeight: 1.6, color: C.meta, fontStyle: 'italic' }}>{data.caption}</figcaption>
    </figure>
  );
}

/* Author box and newsletter sign-up, the two things that sit under a finished
   article. The newsletter has no backend yet, so a submit hands the address to
   the mail client and says so plainly - no fake success state. */
function AuthorAvatar({ size, alt }) {
  const stripe = Math.round(size * 0.17);
  return (
    <span style={{ position: 'relative', display: 'block', width: size, height: size, borderRadius: '50%', overflow: 'hidden', flexShrink: 0 }}>
      <img src={PORTRAIT} alt={alt} style={{ width: '100%', height: '100%', display: 'block', objectFit: 'cover', filter: 'grayscale(1) contrast(1.06)' }} />
      <span aria-hidden="true" style={{ position: 'absolute', left: '38%', top: 0, bottom: 0, width: stripe, background: 'var(--orange-500)', mixBlendMode: 'hard-light', opacity: 0.95 }} />
    </span>
  );
}

function AuthorBox({ s, t, C, dark, onAll }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '132px minmax(0, 1fr)', gap: 28, alignItems: 'start', padding: '26px 0 0', borderTop: `1.5px solid ${C.rule}` }} className="sm-author-box">
      <AuthorAvatar size={132} alt={s.siteName} />
      <div>
        <div className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: C.meta }}>{t.authorLabel}</div>
        <div style={{ marginTop: 10, fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 22, letterSpacing: '-0.02em', color: C.heading }}>{s.siteName}</div>
        <div style={{ marginTop: 4, fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 13.5, color: C.meta }}>{t.authorRole}</div>
        <p style={{ margin: '14px 0 0', maxWidth: '54ch', fontFamily: 'var(--font-body)', fontSize: 16, lineHeight: 1.65, color: C.body, textWrap: 'pretty' }}>{t.authorBio}</p>
        <div style={{ display: 'flex', alignItems: 'center', gap: 20, marginTop: 18, flexWrap: 'wrap' }}>
          <button onClick={onAll} style={{ border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 14, color: C.heading }}>{t.authorMore} →</button>
          <a href={CONTACT.linkedin} target="_blank" rel="noopener noreferrer" style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 14, color: C.meta, textDecoration: 'none' }}>{t.authorLinkedin}</a>
        </div>
      </div>
    </div>
  );
}

function NewsletterBox({ t, C, dark }) {
  const [sent, setSent] = React.useState(false);
  const submit = (e) => {
    e.preventDefault();
    const mail = (new FormData(e.currentTarget).get('email') || '').toString().trim();
    if (!mail) return;
    setSent(true);
    window.location.href = `mailto:${CONTACT.email}?subject=${encodeURIComponent('Newsletter')}&body=${encodeURIComponent(mail)}`;
  };
  const field = { flex: 1, minWidth: 200, minHeight: 48, padding: '0 18px', borderRadius: 999, border: `1.5px solid ${C.rule}`, background: dark ? 'rgba(255,255,255,0.05)' : 'var(--white)', fontFamily: 'var(--font-body)', fontSize: 15.5, color: C.heading, outline: 'none' };
  return (
    <div style={{ marginTop: 40, padding: 'clamp(24px, 3.4vw, 34px)', borderRadius: 'var(--radius-card)', background: C.card, border: `1.5px solid ${C.rule}` }}>
      <div className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: 'var(--orange-500)' }}>{t.newsletterLabel}</div>
      <h3 style={{ margin: '12px 0 0', fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(21px, 2.4vw, 27px)', lineHeight: 1.15, letterSpacing: '-0.02em', color: C.heading }}>{t.newsletterTitle}</h3>
      <p style={{ margin: '12px 0 0', maxWidth: '54ch', fontFamily: 'var(--font-body)', fontSize: 16, lineHeight: 1.65, color: C.body, textWrap: 'pretty' }}>{t.newsletterNote}</p>
      {sent ? (
        <p style={{ margin: '20px 0 0', fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 17, color: C.heading }}>{t.newsletterDone}</p>
      ) : (
        <form onSubmit={submit} style={{ display: 'flex', gap: 10, marginTop: 20, flexWrap: 'wrap' }}>
          <input name="email" type="email" required placeholder={t.newsletterField} style={field} />
          <button type="submit" style={{ minHeight: 48, padding: '0 24px', borderRadius: 999, border: 'none', cursor: 'pointer', background: 'var(--orange-500)', color: 'var(--white)', fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 15 }}>{t.newsletterBtn}</button>
        </form>
      )}
      <p style={{ margin: '14px 0 0', fontFamily: 'var(--font-body)', fontSize: 13, lineHeight: 1.55, color: C.meta }}>{t.newsletterSmall}</p>
    </div>
  );
}

/* Article hero: a small joke rather than a stock plate. Twelve identical
   figures queue on the left, a humming grey box swallows the middle of them,
   and four survivors stand on the right holding the props of their new jobs -
   a NO sign, a red pen, a spanner and an oversized ear. Built from circles and
   rounded rectangles so it stays in the brand's flat vocabulary. */
function Figure({ scale = 1, opacity = 1, delay = 0, bob = false, prop = null }) {
  const w = 14 * scale;
  return (
    <div style={{ position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 * scale, opacity, animation: bob ? `sm-bob 3.4s ${delay}s ease-in-out infinite` : 'none' }}>
      {prop}
      <div style={{ width: w * 0.62, height: w * 0.62, borderRadius: '50%', background: 'var(--white)' }} />
      <div style={{ width: w, height: w * 1.25, borderRadius: `${w * 0.42}px ${w * 0.42}px ${w * 0.16}px ${w * 0.16}px`, background: 'var(--white)' }} />
    </div>
  );
}

function ArticleHero({ post }) {
  const ink = 'var(--white)';
  const props = [
    /* NO sign */
    <div key="no" style={{ width: 17, height: 17, borderRadius: '50%', border: `2.5px solid ${ink}`, position: 'relative', marginBottom: 4 }}>
      <span style={{ position: 'absolute', left: -1, top: 5.5, width: 16, height: 2.5, background: ink, transform: 'rotate(-40deg)' }} />
    </div>,
    /* red pen, held up */
    <div key="pen" style={{ width: 5, height: 20, marginBottom: 4, borderRadius: 2, background: ink, position: 'relative' }}>
      <span style={{ position: 'absolute', left: 0, bottom: -4, width: 5, height: 5, background: 'var(--orange-500)', clipPath: 'polygon(50% 100%, 0 0, 100% 0)' }} />
    </div>,
    /* spanner */
    <div key="wr" style={{ width: 6, height: 20, marginBottom: 4, borderRadius: 2, background: ink, position: 'relative' }}>
      <span style={{ position: 'absolute', left: -3, top: -3, width: 12, height: 8, borderRadius: 3, border: `2.5px solid ${ink}`, borderBottomColor: 'transparent', background: 'transparent' }} />
    </div>,
    /* oversized ear */
    <div key="ear" style={{ width: 18, height: 20, marginBottom: 4, borderRadius: '60% 40% 45% 55% / 55% 55% 45% 45%', border: `2.5px solid ${ink}`, position: 'relative' }}>
      <span style={{ position: 'absolute', left: 5, top: 6, width: 6, height: 8, borderRadius: '50%', border: `2px solid ${ink}`, borderRightColor: 'transparent' }} />
    </div>,
  ];
  return (
    <div className="sm-article-hero" style={{ position: 'relative', margin: '40px 0 0', borderRadius: 'var(--radius-card)', overflow: 'hidden', background: post.art, minHeight: 300, display: 'flex', alignItems: 'flex-end' }}>
      <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(120% 90% at 14% 6%, rgba(255,255,255,0.26), rgba(255,255,255,0) 62%)' }} />
      <div style={{ position: 'relative', display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 'clamp(12px, 2.5vw, 26px)', width: '100%', boxSizing: 'border-box', padding: '0 clamp(18px, 4vw, 40px) clamp(28px, 5vh, 46px)' }}>
        {/* the queue */}
        <div style={{ display: 'flex', alignItems: 'flex-end', gap: 7, flexWrap: 'nowrap', minWidth: 0, overflow: 'hidden' }}>
          {[0, 1, 2, 3, 4, 5, 6, 7].map((i) => (
            <Figure key={i} scale={0.72} opacity={0.34 - i * 0.03} />
          ))}
        </div>
        {/* the box that hums */}
        <div style={{ width: 62, height: 46, borderRadius: 8, background: 'rgba(255,255,255,0.16)', border: '1.5px solid rgba(255,255,255,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5, flexShrink: 0 }}>
          {[0, 1, 2].map((i) => (
            <span key={i} style={{ width: 5, height: 5, borderRadius: '50%', background: ink, animation: `sm-blink 1.6s ${i * 0.22}s ease-in-out infinite` }} />
          ))}
        </div>
        {/* the survivors */}
        <div style={{ display: 'flex', alignItems: 'flex-end', gap: 'clamp(10px, 2vw, 20px)', flexShrink: 0 }}>
          {props.map((pr, i) => (
            <Figure key={i} scale={1.5} bob delay={i * 0.35} prop={pr} />
          ))}
        </div>
      </div>
    </div>
  );
}

function ArticleReader({ s, t, post, onBack, onOpenArticle }) {
  const { Icon } = window.SevcikMarketingDesignSystem_3203fa;
  const p = post || s.posts[0];
  const [shown, setShown] = React.useState(false);
  const [progress, setProgress] = React.useState(0);
  const [backHover, setBackHover] = React.useState(false);
  /* Reader theme is shared with the hub and case studies via useReaderTheme. */
  const theme = useReaderTheme();
  const { dark, C } = theme;
  const flipDark = theme.flip;
  const scroller = React.useRef(null);
  const idx = s.posts.findIndex((x) => x.id === p.id);
  const next = s.posts[(idx + 1) % s.posts.length];

  React.useEffect(() => {
    const id = requestAnimationFrame(() => setShown(true));
    const to = setTimeout(() => setShown(true), 60);
    const onKey = (e) => { if (e.key === 'Escape') onBack(); };
    window.addEventListener('keydown', onKey);
    const prev = document.documentElement.style.overflow;
    document.documentElement.style.overflow = 'hidden';
    return () => { cancelAnimationFrame(id); clearTimeout(to); window.removeEventListener('keydown', onKey); document.documentElement.style.overflow = prev; };
  }, [onBack]);
  React.useEffect(() => { if (scroller.current) scroller.current.scrollTop = 0; setProgress(0); }, [p.id]);

  const onScroll = (e) => {
    const el = e.currentTarget;
    const max = el.scrollHeight - el.clientHeight;
    setProgress(max > 0 ? Math.min(1, el.scrollTop / max) : 0);
  };

  const body = { margin: 0, fontFamily: 'var(--font-body)', fontSize: 19, lineHeight: 1.75, color: C.body };
  const h2 = { margin: '16px 0 -8px', fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 30, lineHeight: 1.2, letterSpacing: '-0.015em', color: C.heading };

  return (
    <div ref={scroller} onScroll={onScroll} className="sm-reader-layer"
      style={{
        position: 'fixed', inset: 0, zIndex: 80, background: C.bg, overflowY: 'auto',
        opacity: shown ? 1 : 0, transform: shown ? 'translateX(0)' : 'translateX(56px)',
        transition: 'opacity .4s ease, transform .5s cubic-bezier(.22,1,.36,1), background-color .35s ease',
      }}>
      <div style={{ position: 'fixed', top: 0, left: 0, right: 0, height: 3, zIndex: 2 }}>
        <div style={{ height: '100%', width: `${progress * 100}%`, background: C.progress, transition: 'width .1s linear' }}></div>
      </div>
      <div style={{ position: 'relative', zIndex: 1, background: C.bg, borderBottom: `1.5px solid ${C.rule}`, transition: 'background-color .35s ease' }}>
        <div style={{ maxWidth: 1080, margin: '0 auto', padding: '14px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 20 }}>
          <button onClick={onBack} onMouseEnter={() => setBackHover(true)} onMouseLeave={() => setBackHover(false)}
            style={{ display: 'flex', alignItems: 'center', gap: 10, minHeight: 44, border: 'none', background: 'transparent', cursor: 'pointer', padding: 0, fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: backHover ? C.heading : C.stand, transition: 'color .25s ease' }}>
            <span style={{ width: 32, height: 32, borderRadius: 'var(--radius-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: backHover ? C.chipHover : C.chip, transition: 'background-color .25s ease' }}>
              <Icon name="arrow-up-left" size={15} color={backHover ? C.chipInkHover : C.chipInk} />
            </span>
            {t.backArticles}
          </button>
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <span className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: C.meta }}>{p.read} {t.read}</span>
            <button onClick={flipDark} aria-label={dark ? t.lightMode : t.darkMode} title={dark ? t.lightMode : t.darkMode}
              style={{ width: 32, height: 32, minHeight: 32, borderRadius: 'var(--radius-card)', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: C.chip, color: C.chipInk, fontSize: 14, lineHeight: 1, transition: 'background-color .25s ease, color .25s ease' }}>
              {dark ? '\u2600' : '\u263E'}
            </button>
          </div>
        </div>
      </div>
      <article style={{ maxWidth: 720, margin: '0 auto', padding: '72px 24px 40px' }}>
        <div className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: C.meta }}>{p.category} · {p.date}</div>
        <h1 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(36px, 4.4vw, 56px)', lineHeight: 1.06, letterSpacing: '-0.025em', color: C.heading, margin: '18px 0 0' }}>{p.title}</h1>
        <p style={{ fontFamily: 'var(--font-display)', fontWeight: 400, fontSize: 23, lineHeight: 1.5, color: C.stand, margin: '20px 0 0' }}>{p.standfirst}</p>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '32px 0 0', paddingTop: 24, borderTop: `1.5px solid ${C.rule}` }}>
          <AuthorAvatar size={40} alt={s.siteName} />
          <div>
            <div style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 14, color: C.heading }}>{s.siteName}</div>
            <div style={{ fontFamily: 'var(--font-meta)', fontWeight: 500, fontSize: 12.5, color: C.meta }}>{t.authorRole}</div>
          </div>
        </div>
        <ArticleHero post={p} />
        <div style={{ marginTop: 44, display: 'flex', flexDirection: 'column', gap: 28 }}>
          {(p.blocks || []).map((bl, i) => (
            bl.k === 'h' ? <h2 key={i} style={h2}>{bl.t}</h2>
              : bl.k === 'q' ? <blockquote key={i} style={{ margin: 0, padding: '4px 0 4px 24px', borderLeft: `2px solid ${C.heading}`, fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 22, lineHeight: 1.45, color: C.heading }}><Em text={bl.t} /></blockquote>
                : bl.k === 'ul' ? <ArticleList key={i} items={bl.items} C={C} />
                  : bl.k === 'stat' ? <StatCallout key={i} value={bl.value} label={bl.t} C={C} />
                    : bl.k === 'fig' ? <TeamShape key={i} data={bl.fig} C={C} dark={dark} />
                      : <p key={i} style={body}><Em text={bl.t} /></p>
          ))}
        </div>
      </article>
      <div style={{ maxWidth: 720, margin: '0 auto', padding: '8px 24px 56px' }}>
        <AuthorBox s={s} t={t} C={C} dark={dark} onAll={onBack} />
        <NewsletterBox t={t} C={C} dark={dark} />
      </div>
      {next && next.id !== p.id && (
      <div style={{ maxWidth: 720, margin: '0 auto', padding: '0 24px 96px' }}>
        <div style={{ borderTop: `1.5px solid ${C.rule}`, paddingTop: 28 }}>
          <div className="sm-mono" style={{ fontFamily: 'var(--font-mono)', fontWeight: 500, fontSize: 9.5, letterSpacing: 'var(--tracking-label)', textTransform: 'uppercase', color: C.meta, marginBottom: 14 }}>{t.readNext}</div>
          <PostRow post={next} t={t} href={routeHref({ lang: s.htmlLang, screen: 'blog', slug: next.slug })} onOpen={() => onOpenArticle(next)} last dark={dark} />
        </div>
      </div>
      )}
    </div>
  );
}

Object.assign(window, { BlogListing, ArticleReader, PostRow, FeaturedPost });
